package su.msk.jet.team01.chatik.server;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import su.msk.jet.team01.chatik.server.commands.*;
import su.msk.jet.team01.chatik.server.data.Client;
import su.msk.jet.team01.chatik.server.exception.CommandNotFoundException;
import su.msk.jet.team01.chatik.server.exception.InvalidArgsCountException;
import su.msk.jet.team01.chatik.server.exception.InvalidArgumentException;

import java.util.HashMap;
import java.util.Map;

public class CommandProcessor {

	private static Map<String, Command> commands = new HashMap<String, Command>();
	private static CommandProcessor instance = null;

	private static Logger logger = LoggerFactory.getLogger(CommandProcessor.class);

	static {
		addCommand(new ListRoomsCommand());
		addCommand(new ChangeRoomCommand());
		addCommand(new ChangeNameCommand());
		addCommand(new SendPrivateCommand());
		addCommand(new SendMessageCommand());
		addCommand(new GetHistoryCommand());
		addCommand(new HelpCommand());
		addCommand(new ByeCommand());
	}
	
	private static void addCommand(Command command) {
		commands.put(command.getName(), command);
	}

	public static CommandProcessor get() {
		if (instance == null) {
			instance = new CommandProcessor();
		}
		return instance;
	}

	private Command getCommand(String name) throws CommandNotFoundException {
		Command command;
		
		command = commands.get(name);
		if(command == null) {
			throw new CommandNotFoundException("Command " + name + " not found");
		}
		
		return command;
	}
	
	private String[] extractArgs(final String input, final int argsCount) throws InvalidArgsCountException {
		String argsString = input.replaceAll("(^/\\S+\\s*|\\s+$)", "");
		String[] result = argsString.split("\\s+", argsCount);
		
		if(result.length < argsCount) {
			throw new InvalidArgsCountException("Invalid args count given (" + result.length + "/" + argsCount + ")");
		}
		
		return result;
	}
	
	public void process(final Client client, final String input) {
		Command command;
		String commandString;

		if (input.isEmpty()) {
			logger.warn("Cheater detected! Client " + client + " sent empty message");
			return;
		}

		logger.info(client + ": " + input);
		commandString = input.replaceAll("(^[^/].*|(/|[^\\S+][\\s\\S]*))", "");
		try {
			command = getCommand(commandString.isEmpty() ? "msg" : commandString);
			command.execute(client, extractArgs(input, command.getArgsCount()));
		} catch (CommandNotFoundException e) {
			client.send("Unknown command");
		} catch (InvalidArgsCountException e) {
			client.send("Bad syntax");
		} catch (InvalidArgumentException e) {
			client.send("Bad syntax");
		}
	}
}
